/**
 * Copyright (C), 2015-2018, XXX有限公司
 * FileName: CpConfigService
 * Author:   sjkyll
 * Date:     2018-08-01 12:28
 * Description: 处理cp配置信息
 * <author>          <time>          <version>          <desc>
 * 作者姓名         修改时间           版本号            描述
 */
package com.cdqidi.smsservice.service;

import com.cdqidi.smsservice.domain.CpConfig;
import com.cdqidi.smsservice.dto.AccessToken;
import com.cdqidi.smsservice.dto.AjaxResult;
import com.cdqidi.smsservice.exception.ApiException;
import com.cdqidi.smsservice.service.auth.CacheData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 〈一句话功能简述〉<br>
 *
 * @author sjkyll
 * @create 2018-08-01 12:28
 * @since 1.0.0
 */
@Service
@Slf4j
public class CpConfigService {
    @Autowired
    private CacheService cacheService;
    @Value(value = "${auth.token_expire}")
    private Long expire;
    @Value(value = "${auth.old_token_expire}")
    private Long oldTokenExpire;

    private final Map<String, CacheData<AccessToken>> map = new ConcurrentHashMap<>();
    private final Map<String, String> tokenMaps = new ConcurrentHashMap<>();

    public CacheData<AccessToken> getAccessToken(String appId, String appSecret) throws ApiException {
        CacheData<AccessToken> cacheData = map.get("appId_" + appId);
        Optional<CpConfig> cpConfigOptional = cacheService.getCpConfig(appId);
        AccessToken accessToken;
        if (cpConfigOptional.isPresent()) {
            if (!cpConfigOptional.get().getAppSecret().equals(appSecret)) {
                throw new ApiException(AjaxResult.accessTokenError("appSecret不正确"));
            }
            if (null == cacheData) {
                accessToken = createAccessToken(cpConfigOptional.get());
                cacheData = new CacheData<>();
            } else {
                String _accessToken = cacheData.getData().getAccessToken();
                String oldAccessToken = cacheData.getData().getOldAccessToken();

                accessToken = createAccessToken(cpConfigOptional.get());
                accessToken.setOldAccessToken(_accessToken);

                if (null != oldAccessToken && !oldAccessToken.equals(_accessToken)) {
                    synchronized (tokenMaps) {
                        tokenMaps.remove(oldAccessToken);
                    }
                }
            }
            cacheData.setData(accessToken);
            cacheData.setExpire(expire);
            cacheData.setSaveTime(System.currentTimeMillis());
            synchronized (map) {
                map.put("appId_" + appId, cacheData);
            }
            synchronized (tokenMaps) {
                tokenMaps.put(accessToken.getAccessToken(), appId);
            }
        } else {
            throw new ApiException(AjaxResult.accessTokenError("appid不存在"));
        }
        log.debug("调用access_token,old: " + accessToken.getOldAccessToken() + ",new: " + accessToken.getAccessToken());
        for (String s : tokenMaps.keySet()) {
            log.debug("appid: " + tokenMaps.get(s) + ",accessToken: " + s);
        }
        return cacheData;
    }

    public boolean isAccessToken(String accessToken) throws ApiException {
        String appId = tokenMaps.get(accessToken);
        CacheData<AccessToken> cacheData = map.get("appId_" + appId);
        if (null == cacheData) {
            throw new ApiException(AjaxResult.accessTokenError("accessToken不存在"));
        }
        long all = cacheData.getSaveTime() + cacheData.getExpire();
        long currentTime = System.currentTimeMillis();
        log.debug("all: " + all + ",currentTimes: " + currentTime);
        if (cacheData.getExpire() == 0 || currentTime - all > 0) {
            synchronized (map) {
                cacheData.setExpire(0L);
            }
            synchronized (tokenMaps) {
                tokenMaps.remove(accessToken);
            }
            throw new ApiException(AjaxResult.accessTokenError("access_token已过期"));
        }
        all = cacheData.getSaveTime() + oldTokenExpire;
        if (currentTime - all > oldTokenExpire) {
            //旧的token只能存活50秒
            synchronized (tokenMaps) {
                tokenMaps.remove(accessToken);
            }
        }
        for (String s : tokenMaps.keySet()) {
            log.debug("appid: " + tokenMaps.get(s) + ",accessToken: " + s);
        }
        return null != tokenMaps.get(accessToken);
    }

    private AccessToken createAccessToken(CpConfig cpConfig) {
        String accessTok = UUID.randomUUID().toString().replace("-", "");
        AccessToken accessToken = new AccessToken();
        accessToken.setAppId(cpConfig.getAppId());
        accessToken.setAppName(cpConfig.getAppSecret());
        accessToken.setAccessToken(accessTok);
        return accessToken;
    }


    void flushMap() {
        synchronized (map) {
            map.clear();
        }
        synchronized (tokenMaps) {
            tokenMaps.clear();
        }
    }

    void deleteOneCache(String appId) {
        CacheData<AccessToken> cacheData = map.get("appId_" + appId);
        if (null != cacheData) {
            synchronized (tokenMaps) {
                tokenMaps.remove(cacheData.getData().getAccessToken());
                tokenMaps.remove(cacheData.getData().getOldAccessToken());
            }
        }
        synchronized (map) {
            map.remove("appId_" + appId);
        }
    }
}